import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from scipy import ndimage

# 尝试打开图片
face = Image.open('face.png')
th = Image.open('th.png')
im = np.array(face)
im_face = np.array(face)
im_th = np.array(th)
# 打印数组信息
print(f"数组类型: {type(im)}")       # 输出数组类型，应为 numpy.ndarray
print(f"数据类型: {im.dtype}")       # 输出数据类型，通常是 uint8
print(f"图片尺寸(高, 宽, 通道): {im.shape}")  # 输出图片尺寸

# 提取红色通道（仅保留红色，绿、蓝通道置 0 ）
im_red = im.copy()  # 复制原数组，避免修改原图
im_red[:, :, 1] = 0  # 绿色通道置 0
im_red[:, :, 2] = 0  # 蓝色通道置 0

# 显示原图和处理后的图
plt.figure(figsize=(10, 5))  # 设置画布大小，方便对比

# 显示原图
plt.subplot(1, 2, 1)  # 1 行 2 列，第 1 个子图
plt.imshow(im)
plt.title("原图")
plt.axis("off")  # 隐藏坐标轴

# 显示红色通道图
plt.subplot(1, 2, 2)  # 1 行 2 列，第 2 个子图
plt.imshow(im_red)
plt.title("红色通道图")
plt.axis("off")  # 隐藏坐标轴

plt.tight_layout()  # 自动调整布局，避免标签重叠
plt.show()

# 保存处理后的红色通道图片到当前运行目录。
save_filename = "numpy_red.png"
Image.fromarray(im_red).save(save_filename)
print(f"红色通道图片已保存为: {save_filename}")


#灰度图片
# 转换为灰度图（'L'模式表示8位灰度图）
im_gray = np.array(face.convert('L'))  # 灰度图数组（ shape 为 (高, 宽)）
# 打印灰度图数组信息
print(type(im_gray))    # <class 'numpy.ndarray'>
print(im_gray.dtype)    # uint8
print(im_gray.shape)    # (768, 1024) （示例尺寸）

# 展示灰度图（使用gray colormap更符合人眼对灰度的感知）
plt.figure()
plt.imshow(im_gray, cmap='gray')  # 不加cmap可能显示为伪彩色
plt.title('灰度图')
plt.axis('off')  # 隐藏坐标轴
plt.show()

pixel_value = im[200, 300]
print(f"原始像素(200, 300)值：{pixel_value}")
print(f"像素值类型：{type(pixel_value)}")

# 修改像素值为红色 (RGB: 255, 0, 0)
im[200, 300] = [255, 0, 0]
print(f"修改后像素(200, 300)值：{im[200, 300]}")

# 展示修改后的图片
plt.figure()
plt.imshow(im)
plt.title("修改像素后的图片")
plt.axis('off')  # 隐藏坐标轴
plt.show()

R, G, B = im[200, 300]  # 取(200,300)位置的像素
print(f"R通道值: {R}, G通道值: {G}, B通道值: {B}")

# 3. 修改像素值
# 方式1：直接赋值元组（设为黑色）
im[200, 300] = (0, 0, 0)

# 4. 展示修改后的图片
plt.imshow(im)
plt.title("修改像素后的图片")
plt.axis('off')  # 隐藏坐标轴
plt.show()

im_green = im.copy()  # 复制原数组，避免修改原图
im_green[:, :, 0] = 0  # 红色通道置 0
im_green[:, :, 2] = 0  # 蓝色通道置 0

# 显示原图和绿色通道图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(im)
plt.title("原图")
plt.axis("off")

plt.subplot(1, 2, 2)
plt.imshow(im_green)
plt.title("绿色通道图")
plt.axis("off")

plt.tight_layout()
plt.show()

# 保存绿色通道图片
save_filename = "numpy_green.png"
Image.fromarray(im_green).save(save_filename)
print(f"绿色通道图片已保存为: {save_filename}")

# 2. 提取红色通道（修正缩进错误）
im_red = im.copy()  # 此处去除多余缩进，与其他通道代码对齐
im_red[:, :, 1] = 0  # 绿色通道置 0
im_red[:, :, 2] = 0  # 蓝色通道置 0

# 显示原图和红色通道图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(im)
plt.title("原图")
plt.axis("off")

plt.subplot(1, 2, 2)
plt.imshow(im_red)
plt.title("红色通道图")
plt.axis("off")

plt.tight_layout()
plt.show()

#保存红色的通道图片
save_filename = "numpy_red.png"
Image.fromarray(im_red).save(save_filename)
print(f"红色通道图片已保存为: {save_filename}")

# 3. 提取蓝色通道（修正蓝色通道置0的笔误）
im_blue = im.copy()
im_blue[:, :, 0] = 0  # 红色通道置 0
im_blue[:, :, 1] = 0  # 绿色通道置 0（原代码误写为“蓝色通道”，已修正）

# 显示原图和蓝色通道图
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(im)
plt.title("原图")
plt.axis("off")

plt.subplot(1, 2, 2)
plt.imshow(im_blue)
plt.title("蓝色通道图")
plt.axis("off")

plt.tight_layout()
plt.show()

def invert_colors(image_array, mode='rgb'):
    if mode.lower() == 'rgb':
        return 255 - image_array
    else:
        print("错误：不支持的颜色模式。请使用 'rgb'")
        return image_array


# 统一的显示函数（避免重复定义）
def display_images(original, processed, title1="原始图像", title2="处理后图像"):
    plt.figure(figsize=(12, 6))
    plt.subplot(121)
    plt.title(title1)
    plt.imshow(original)
    plt.axis('off')

    plt.subplot(122)
    plt.title(title2)
    plt.imshow(processed)
    plt.axis('off')

    plt.tight_layout()
    plt.show()


# 统一的保存函数（避免重复定义）
def save_image(image_array, output_path):
    img = Image.fromarray(image_array)
    img.save(output_path)
    print(f"图像已保存至: {output_path}")

image = im
inverted_rgb = invert_colors(image, mode='rgb')
display_images(image, inverted_rgb, "原始图像", "颜色反转后的图像")
save_image(inverted_rgb, "inverted_image.jpg")

def color_quantization(image, num_levels):
    # 计算每个等级的间隔
    step = 256 // num_levels
    # 减色处理：将每个像素值映射到最近的等级
    quantized = (image // step) * step
    return quantized.astype(np.uint8)

# 减色为8级（可修改为其他等级，等级越低颜色越简单）
num_levels = 8
quantized_array = color_quantization(im, num_levels)  # 使用im而不是img_array

# 显示原图和减色后的图
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.imshow(im)
plt.title('原图')
plt.axis('off')

plt.subplot(122)
plt.imshow(quantized_array)
plt.title(f'减色后（{num_levels}级）')
plt.axis('off')

plt.show()

# 保存结果
quantized_img = Image.fromarray(quantized_array)
quantized_img.save('减色结果.jpg')

def gamma_correction(image, gamma=2.2):
    """对图像进行伽马校正"""
    # 归一化到 [0, 1] 范围
    image_normalized = image / 255.0
    # 应用伽马校正
    corrected = np.power(image_normalized, 1.0 / gamma)
    # 还原到 [0, 255] 范围
    return (corrected * 255).astype(np.uint8)

# 读取图片（转为RGB格式）
image = np.array(Image.open("face.png").convert("RGB"))

# 应用伽马2.2校正
gamma_corrected = gamma_correction(image, gamma=2.2)

# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image)
plt.title("原图")
plt.axis('off')

plt.subplot(1, 2, 2)
plt.imshow(gamma_corrected)
plt.title("伽马2.2校正后")
plt.axis('off')
plt.show()

def display_images(img1, img2, title1, title2):
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.imshow(img1)
    plt.title(title1)
    plt.axis('off')

    plt.subplot(1, 2, 2)
    plt.imshow(img2)
    plt.title(title2)
    plt.axis('off')
    plt.tight_layout()
    plt.show()


def alpha_blend(foreground, background, alpha=0.5):
    # 输入检查
    if foreground.shape != background.shape:
        raise ValueError("前景和背景图像尺寸不匹配")

    # 转换到float类型
    fg = foreground.astype(float)
    bg = background.astype(float)

    # 执行混合
    blended = alpha * fg + (1.0 - alpha) * bg

    # 确保值在0-255范围内
    return np.clip(blended, 0, 255).astype(np.uint8)

if __name__ == "__main__":
    foreground = np.array(Image.open('face.png').convert('RGB'))
    height, width = foreground.shape[:2]
    background = np.ones((height, width, 3), dtype=np.uint8) * 255
    alpha = 0.7

    # 4. 执行混合
    blended = alpha_blend(foreground, background, alpha)

    # 5. 显示结果
    display_images(foreground, blended, "前景图像", f"混合结果(α={alpha})")

height, width, _ = im.shape
print(f"图片尺寸: 高度={height}, 宽度={width}")

# 3. 定义头部区域（示例参数，需根据实际图片调整）
# 假设头部大约在上半部分1/3处
head_top = 0
head_bottom = height // 2  # 截取上半部分
head_left = width // 5    # 从左侧1/5处开始
head_right = 4 * width //5 # 到右侧2/5处结束

# 4. 截取头部
head = im[head_top:head_bottom, head_left:head_right]

# 5. 显示和保存结果
plt.imshow(head)
plt.title("截取的头部")
plt.axis('off')  # 隐藏坐标轴
plt.show()

print("原始图片尺寸:", im_face.shape)  # (height, width, channels)
print("替换图片尺寸:", im_th.shape)    # 需确保能覆盖头部区域

# 3. 定义头部区域（示例：截取上半部分）
head_top, head_bottom = 0, im_face.shape[0] // 2  # 截取上半部分1/3
head_left, head_right = im_face.shape[1] // 5, 4 * im_face.shape[1] // 5 # 居中宽度

# 4. 调整替换图片大小以匹配头部区域
from PIL import ImageOps
th_resized = ImageOps.fit(th, (head_right - head_left, head_bottom - head_top))
im_th = np.array(th_resized)

# 5. 替换头部区域
im_face[head_top:head_bottom, head_left:head_right] = im_th

# 6. 显示和保存结果
plt.imshow(im_face)
plt.title("替换头部后的图片")
plt.axis('off')
plt.show()

def rotate_image(image, degrees):
    """旋转图片（支持90、180、270度）"""
    if degrees == 90:
        return np.rot90(image, k=1)  # 逆时针90度
    elif degrees == 180:
        return np.rot90(image, k=2)  # 逆时针180度
    elif degrees == 270:
        return np.rot90(image, k=3)  # 逆时针270度
    else:
        raise ValueError("只支持90、180、270度旋转")


# 3. 旋转图片并保存
rotations = [90, 180, 270]
for angle in rotations:
    rotated = rotate_image(im, angle)

    # 显示图片
    plt.figure()
    plt.imshow(rotated)
    plt.title(f"旋转 {angle}度")
    plt.axis('off')
    plt.show()

def generate_blue_noise_mask(size):
    """生成蓝噪声掩模（基于void-and-cluster方法简化版）"""
    # 步骤1：初始随机二进制模式
    mask = np.random.rand(size, size) > 0.5

    # 步骤2：通过滤波优化为蓝噪声特性
    kernel = np.array([[0.05, 0.2, 0.05],
                       [0.2, -1.0, 0.2],
                       [0.05, 0.2, 0.05]])
    for _ in range(10):  # 迭代优化次数
        conv = ndimage.convolve(mask.astype(float), kernel, mode='wrap')
        mask = (conv < 0)  # 更新掩模
    return mask.astype(float)


def dart_blue_noise_sampling(image, sample_ratio=0.3):
    """DART蓝噪声采样"""
    # 转换为灰度图
    if image.ndim == 3:
        gray = np.mean(image, axis=2).astype(float)
    else:
        gray = image.astype(float)

    # 生成蓝噪声掩模
    h, w = gray.shape
    blue_noise = generate_blue_noise_mask(max(h, w))[:h, :w]

    # 归一化并采样
    gray_normalized = (gray - gray.min()) / (gray.max() - gray.min())
    sampled = (gray_normalized > blue_noise * sample_ratio).astype(np.uint8) * 255

    return sampled


# 读取图片
image = np.array(Image.open("face.png").convert("L"))  # 转为灰度图

# 执行蓝噪声采样
sampled = dart_blue_noise_sampling(image, sample_ratio=0.2)

# 显示结果
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.imshow(image, cmap='gray')
plt.title("原图")
plt.axis('off')

plt.subplot(1, 2, 2)
plt.imshow(sampled, cmap='gray')
plt.title("蓝噪声采样结果")
plt.axis('off')
plt.show()

def svd_compress(channel, keep_rate):
    """对单个颜色通道进行压缩，keep_rate为保留的奇异值比例（0-1）"""
    # 分解通道矩阵
    U, s, VT = np.linalg.svd(channel, full_matrices=False)
    # 计算要保留的奇异值数量
    k = int(len(s) * keep_rate)
    k = max(1, k)  # 至少保留1个，避免出错
    # 用前k个奇异值重构通道
    compressed = U[:, :k] @ np.diag(s[:k]) @ VT[:k, :]
    # 确保像素值在0-255范围内
    return np.clip(compressed, 0, 255).astype(np.uint8)

def compress_image(img, keep_rate):
    """对彩色图像压缩，按比例保留每个通道的奇异值"""
    # 分离RGB三个通道
    r = img[:, :, 0]
    g = img[:, :, 1]
    b = img[:, :, 2]

    # 每个通道单独压缩
    r_comp = svd_compress(r, keep_rate)
    g_comp = svd_compress(g, keep_rate)
    b_comp = svd_compress(b, keep_rate)

    # 合并通道得到彩色图像
    return np.stack([r_comp, g_comp, b_comp], axis=2)

def show_images(original, comp_50, comp_25, comp_10, comp_1):
    """展示不同压缩率的效果对比"""
    plt.figure(figsize=(10, 12))  # 设定画布大小

    # 显示原图
    plt.subplot(3, 2, 1)
    plt.imshow(original)
    plt.title("原始图像")
    plt.axis('off')

    # 显示各压缩率图像
    plt.subplot(3, 2, 2)
    plt.imshow(comp_50)
    plt.title("50%压缩率")
    plt.axis('off')

    plt.subplot(3, 2, 3)
    plt.imshow(comp_25)
    plt.title("25%压缩率")
    plt.axis('off')

    plt.subplot(3, 2, 4)
    plt.imshow(comp_10)
    plt.title("10%压缩率")
    plt.axis('off')

    plt.subplot(3, 2, 5)
    plt.imshow(comp_1)
    plt.title("1%压缩率")
    plt.axis('off')

    plt.tight_layout()
    plt.show()

if __name__ == "__main__":
    # 加载图像
    face = Image.open('face.png')
    im = np.array(face)  # 转换为NumPy数组

    # 定义要测试的压缩率（对应保留的奇异值比例）
    rates = [0.5, 0.25, 0.1, 0.01]

    # 生成不同压缩率的图像
    comp_50 = compress_image(im, rates[0])
    comp_25 = compress_image(im, rates[1])
    comp_10 = compress_image(im, rates[2])
    comp_1 = compress_image(im, rates[3])

    # 显示对比结果
    show_images(im, comp_50, comp_25, comp_10, comp_1)


